package cn.lhn.ridersclub.service;

import cn.lhn.ridersclub.entity.Account;
import cn.lhn.ridersclub.entity.Grade;
import cn.lhn.ridersclub.mapper.AccountMapper;
import cn.lhn.ridersclub.mapper.GradeMapper;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Hashtable;
import java.util.Map;

@Service
public class GradeServiceImpl implements GradeService {

    private static final Map<Long, Long> MGV_MAP = new Hashtable<>();

    static {
        MGV_MAP.put(1L, 200L);
        MGV_MAP.put(2L, 600L);
        MGV_MAP.put(3L, 1200L);
        MGV_MAP.put(4L, 2000L);
        MGV_MAP.put(5L, 3000L);
        MGV_MAP.put(6L, 4200L);
        MGV_MAP.put(7L, 5600L);
        MGV_MAP.put(8L, 7200L);
        MGV_MAP.put(9L, 9000L);
        MGV_MAP.put(10L, Long.MAX_VALUE);
    }

    private final GradeMapper gradeMapper;

    private final AccountMapper accountMapper;

    private final RedisService redisService;

    public GradeServiceImpl(GradeMapper gradeMapper, AccountMapper accountMapper, RedisService redisService) {
        this.gradeMapper = gradeMapper;
        this.accountMapper = accountMapper;
        this.redisService = redisService;
    }

    @Override
    public void incr(Long accountId) {
        Account account = accountMapper.selectById(accountId);
        if (account == null) {
            throw new RuntimeException("账号不存在");
        }

        Grade grade = gradeMapper.selectById(accountId);
        if (grade == null) {
            grade = Grade
                    .builder()
                    .id(account.getId())
                    .grade(1L)
                    .currentGradeValue(140L)
                    .build();
        }

        long g = grade.getGrade();
        Long maxGradeValue = MGV_MAP.get(g);
        long currentGradeValue = grade.getCurrentGradeValue();
        //  如果当前经验值为最大值，则不增加
        if (Long.MAX_VALUE - currentGradeValue >= 10) {
            currentGradeValue += 10;
        }

        //  如果当前经验值 + 新增的经验值大于最大经验值，则等级 + 1
        if (currentGradeValue > maxGradeValue) {
            g++;
        }
        grade.setGrade(g);
        grade.setCurrentGradeValue(currentGradeValue);
        grade.setUpdateTime(LocalDateTime.now());

        //  更新数据
        gradeMapper.updateById(grade);
    }

    @Override
    public void incrForLogin(Long accountId) {
        Account account = accountMapper.selectById(accountId);
        if (account == null) {
            throw new RuntimeException("账号不存在");
        }

        //  查询今日是否已经登录
        Object o = redisService.get("grade:incr:login:" + accountId);
        if (o == null) {
            incr(accountId);
            return;
        }

        String s = String.valueOf(o);
        try {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime time = LocalDateTime.parse(s);
            Duration duration = Duration.between(time, now);
            if (duration.toHours() >= 24) {
                //  当上一次登录事件超过24小时，则增加经验值
                incr(accountId);
                // 更新登录事件
                redisService.set("grade:incr:login:" + accountId, now.toString());
            }
        }
        catch (Exception ignore) {

        }
    }

    @Override
    public Grade getGrade(Long accountId) {
        Account account = accountMapper.selectById(accountId);
        if (account == null) {
            return Grade
                    .builder()
                    .id(accountId)
                    .grade(0L)
                    .currentGradeValue(0L)
                    .updateTime(LocalDateTime.now())
                    .build();
        }

        Grade grade = gradeMapper.selectById(accountId);
        if (grade == null) {

            grade = Grade
                    .builder()
                    .id(account.getId())
                    .grade(1L)
                    .currentGradeValue(140L)
                    .updateTime(LocalDateTime.now())
                    .build();

            gradeMapper.insert(grade);
        }

        return grade;
    }

    @Override
    public Long getMaxGradeValue(Long grade) {
        Long max = MGV_MAP.get(grade);
        return max == null ? Long.MAX_VALUE : max;
    }
}
